package com.headcaselabs.work;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.headcaselabs.orchestra.JobUtils;

/**
 * Monitor ensures that a Future-task does not exceed it's maximum amount of processing time
 * 
 * @author Florian Leibert
 * 
 */
public class Monitor implements Callable<Boolean>, Monitorable {
    private Monitorable supervisee;

    private long maximumTime;

    private long starttime;

    private String id;

    private boolean finished = false;

    private boolean cancelled = false;
    

    protected transient Future<?> future;
    

    private final static Log log_ =
      LogFactory.getLog(Monitor.class.getName());

    /**
     * Constructor
     * 
     * @param supervisee
     * @param jobId
     * @param maximumTime
     */
    public Monitor(Monitorable supervisee, String monitorId, long maximumTime) {
        id = monitorId;
        this.maximumTime = maximumTime;
        this.supervisee = supervisee;
        cancelled = false;
    }

    /**
     * @See {@link Callable}{@link #call()}
     */
    public Boolean call() throws Exception {
        starttime = System.currentTimeMillis();
        Thread.sleep(maximumTime);
        if (!cancelled) {
        		synchronized(JobUtils.myLock) {
            		log_.debug("Monitor awoke. Supervisee is:"+supervisee.getId());
                finished = true;
                setFuture(null);
                if (!supervisee.getIsFinished()) {
                	log_.info("Supervisee didn't finish. Killing supervisee:"+supervisee.getId());
                  supervisee.cancel();
                  return false;
                } else {
                    return true;
                }
                
            }
        } else {
            return true;
        }
        
    }

    /**
     * @return the cancelled.
     */
    public synchronized boolean isCancelled() {
        return cancelled;
    }

    /**
     * @param cancelled
     *            The cancelled to set.
     */
    public synchronized void setCancelled(boolean cancelled) {
        this.cancelled = cancelled;
    }

    public void cancel() {
    	synchronized(JobUtils.myLock) {
    		log_.info("Monitor is being cancelled. Supervisee is:"+supervisee.getId());
        cancelled = true;
        //Future<?> me = JobUtils.getFuture(this);
        getFuture().cancel(true);
        //me.cancel(true);
        //JobUtils.removeFuture(this);
        setFuture(null);
        log_.info("Monitor status: cancelled!");
    	}
    }

    public String getId() {
        return id;
    }

    public boolean getIsFinished() {
        return finished;
    }

    public long getStartTime() {
        return starttime;
    }

    public boolean getWasInterrupted() {
        return cancelled;
    }

    public void registerSupervisee(Monitorable supervisee) {
        this.supervisee = supervisee;
    }

		public Future<?> getFuture() {
			return future;
		}

		public void setFuture(Future<?> future) {
			this.future = future;
		}


}
